/**
 * Created with IntelliJ IDEA.
 *
 * @Auther: 邹陆川
 * @Date: 2021/04/20/9:31 下午
 * @Description:
 */


import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Stack;

/**
 *使用栈
 * 定义计算类
 * 核心思想：使用一个栈来存储操作符和括号，一个栈来存储数值
 * */
public class calculatorExpression {
    public static void main(String[] args) {
        String ex = "10/3";
        double re = calculator(ex);
        System.out.println(re);
    }


    private static double calculator(String expression){
        //定义字符来获取上一个操作数，用于判断是否是括号内第一个为负号的值
        char z = 'c';
        Stack operatorStack = new Stack();//存储操作符
        Stack operandStack = new Stack();//存储操作数
        //-4+3+(6-10+2*3+(-6-6))*4
        //遍历表达式中的操作数和操作符
        for(int i = 0; i < expression.length(); i++){
            char cc = expression.charAt(i);
            if(i>0){z = expression.charAt(i-1);}
            //如果cc是数字
            if(Character.isDigit(cc) || cc == '.' || (i == 0 && cc == '-') || (cc == '-' && z == '(')){
                //取出操作数
                StringBuilder sb = new StringBuilder();
                //只要是数字
                while(Character.isDigit(cc) || cc == '.' || (i == 0 && cc == '-') || (cc == '-' && z == '(')){
                    z = 'c';
                    sb.append(cc);
                    i++;//取下一个字符
                    if(i>=expression.length()){//表达式结束了
                        break;
                    }
                    cc = expression.charAt(i);
                }
                operandStack.push(sb.toString());//操作数入栈
                //修正i的值
                i--;
            }else{//r如果是操作符
                //栈为空
                if(operatorStack.isEmpty()){
                    operatorStack.push(cc);
                    continue;
                }
                //操作符栈中不为空
                while (!operatorStack.isEmpty()){
                    //System.out.println(operatorStack);
                    char op1 = (char) operatorStack.peek();
                    //判断优先级
                    if(compareOperator(op1,cc) < 0){
                        //当前运算符的优先级高于栈顶运算符的优先级（入栈）
                        operatorStack.push(cc);
                        break;
                    }else if(compareOperator(op1,cc) == 0){
                        //当前运算符优先级与栈顶优先级相等，只有一种情况，左一半小括弧遇到右一半小括弧
                        operatorStack.pop();//栈中一半小括弧出栈
                        break;
                    }else{
                        //栈顶运算符优先级高
                        //取出两个操作数
                        if(operandStack.isEmpty()){
                            throw  new RuntimeException("表达式错误！");
                        }
                        Double num1 = Double.parseDouble(operandStack.pop().toString());
                        if(operandStack.isEmpty()){
                            throw  new RuntimeException("表达式错误！");
                        }
                        double num2 = Double.parseDouble(operandStack.pop().toString());
                        //取栈顶运算符
                        char operator = (char) operatorStack.pop();
                        //计算 num1 operator num2;
                        double result = compute(operator,num1,num2);
                        //把结果存储到操作数栈中
                        operandStack.push(result);
                        //如果当前操作符栈为空，新的操作符应该入栈
                        if(operatorStack.isEmpty()){
                            operatorStack.push(cc);
                            break;
                        }
                    }
                }

            }
        }

        //当表达式遍历完后，如果操作符栈不为空，需要继续计算
        while(!operatorStack.isEmpty()){
            char operator = (char)operatorStack.pop();
            //如果操作数栈为空，表达式错误
            if(operandStack.isEmpty()){
                throw  new RuntimeException("表达式错误！");
            }
            double num1 = Double.parseDouble(operandStack.pop().toString());
            if(operandStack.isEmpty()){
                throw  new RuntimeException("表达式错误！");
            }
            double num2 = Double.parseDouble(operandStack.pop().toString());
            double result = compute(operator,num1,num2);
            operandStack.push(result);
        }

        //当操作符栈为空，操作数栈多于一个数，表达式错误
        if(operandStack.size() > 1){
            throw  new RuntimeException("表达式错误！");
        }
        return Double.parseDouble(operandStack.pop().toString());
    }

    //返回计算结果
    private static double compute(char operator, double num2, double num1) {

        switch (operator){
            case '+':
                return num1 + num2;
            case '-':
                return num1 - num2;
            case '*':
                return num1 * num2;
            case '/':
                BigDecimal bigDecimal1 = new BigDecimal(num1);
                BigDecimal bigDecimal2 = new BigDecimal(num2);
                return Double.parseDouble(bigDecimal1.divide(bigDecimal2,5, RoundingMode.HALF_UP)+"");
        }
        return 0;
    }

    //判断两个运算符优先级,如果op1优先级高返回1，op2优先级高返回-1，相等返回0
    private static int compareOperator(char op1, char op2) {
        if(op1 == '+' || op1 == '-'){
            if(op2 == '*' || op2 == '/' || op2 == '('){
                return -1;
            }
        }
        if(op1 == '*' || op1 == '/'){
            if(op2 == '('){
                return -1;
            }
        }
        if(op1 == '('){
            if(op2 == ')'){
                return 0;
            }else{
                return -1;
            }
        }
        return 1;
    }

    ////定义一个方法来检测double类型的数据小数点后面是否有值
    private  static boolean isEmptyByPoint(String str){

        String[] s = str.split("\\.");
        //判断最后一个字符串是否为括弧
        if(s[1].length()<13){
            if(s[1].indexOf(')') == -1){
                try {
                    Integer.parseInt(s[1]);
                }catch (NumberFormatException e){
                    return true;
                }
                return Integer.parseInt(s[1])>0;
            }else{
                //先去掉最后一个字符
                s[1] = s[1].substring(0,s[1].length()-1);
                try {
                    Integer.parseInt(s[1]);
                }catch (NumberFormatException e){
                    return true;
                }
                return Integer.parseInt(s[1])>0;
            }
        }
        return false;
    }


}

